package com.ly.wxPay.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPayUtil;
import com.ly.common.core.bean.R;
import com.ly.wxPay.bean.dto.OrderRefundsDTO;
import com.ly.wxPay.bean.dto.WxOrderDTO;
import com.ly.wxPay.bean.entity.WxOrder;
import com.ly.wxPay.bean.entity.WxRefund;
import com.ly.wxPay.bean.vo.NativeCodeVO;
import com.ly.wxPay.bean.vo.OrderVO;
import com.ly.wxPay.config.properties.WxPayProperties;
import com.ly.wxPay.enums.OrderStatus;
import com.ly.wxPay.enums.WxApiType;
import com.ly.wxPay.enums.WxNotifyType;
import com.ly.wxPay.enums.WxTradeState;
import com.ly.wxPay.service.IWxOrderService;
import com.ly.wxPay.service.IWxPaymentService;
import com.ly.wxPay.service.IWxRefundService;
import com.ly.wxPay.service.IWxService;
import com.ly.wxPay.util.HttpClientUtils;
import com.ly.wxPay.util.HttpUtils;
import com.ly.wxPay.util.OrderNoUtils;
import com.ly.wxPay.util.WechatPay2ValidatorForRequest;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 支付-核心-impl
 *
 * @author luoyun
 * @Date: 2025/11/22 13:49
 * @Note:
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WxServiceImpl implements IWxService {

    private final WxPayProperties wxPayProperties;
    private final CloseableHttpClient wxPayClient;
    private final Verifier verifier;

    private final IWxOrderService orderService;
    private final IWxPaymentService paymentService;
    private final IWxRefundService refundService;

    ReentrantLock lock = new ReentrantLock();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R nativePay(WxOrderDTO dto) {
        log.info("生成订单");
        WxOrder wxOrder = orderService.addOrder(dto);
        String codeUrl = wxOrder.getCodeUrl();
        if (StrUtil.isNotEmpty(codeUrl)) {
            log.info("订单中二维码已存在，直接返回二维码");
            NativeCodeVO vo = NativeCodeVO.builder().codeUrl(codeUrl).orderNo(wxOrder.getOrderNo()).build();
            return R.ok(vo);
        }
        log.info("调用统一下单API");
        // 调用统一下单API
        HttpPost httpPost = new HttpPost(wxPayProperties.getDomain().concat(WxApiType.NATIVE_PAY.getType()));
        // 请求body参数
        Map paramsMap = new HashMap();
        paramsMap.put("appid", wxPayProperties.getAppid());
        paramsMap.put("mchid", wxPayProperties.getMchId());
        paramsMap.put("description", wxOrder.getTitle());
        paramsMap.put("out_trade_no", wxOrder.getOrderNo());
        paramsMap.put("notify_url", wxPayProperties.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType()));
        Map amountMap = new HashMap();
        amountMap.put("total", wxOrder.getTotalFee());
        amountMap.put("currency", "CNY");
        paramsMap.put("amount", amountMap);
        // 将参数转换成json字符串
        String jsonParams = JSONUtil.toJsonStr(paramsMap);
        // 微信支付请求参数 ===> {}{"amount":{"currency":"CNY"},"mchid":"1558950191","out_trade_no":"ORDER_20251122192958257","appid":"wx74862e0dfcf69954","description":"魅雪冰城","notify_url":"https://500c-219-143-130-12.ngrok.io/api/wx-pay/native/notify"}
        //  Consume Time：0 ms 2025-11-22 19:29:58
        /**
         * 微信支付请求参数 ===> {}{"amount":{"total":1,"currency":"CNY"},"mchid":"1558950191","out_trade_no":"ORDER_20251122192958257","appid":"wx74862e0dfcf69954","description":"魅雪冰城","notify_url":"https://500c-219-143-130-12.ngrok.io/api/wx-pay/native/notify"}
         * 微信支付请求参数 ===> {}{"amount":{"total":1,"currency":"CNY"},"mchid":"1558950191","out_trade_no":"ORDER_20251122193359631","appid":"wx74862e0dfcf69954","description":"Java课程","notify_url":"https://500c-219-143-130-12.ngrok.io/api/wx-pay/native/notify"}
         */
        log.info("微信支付请求参数 ===> {}", jsonParams);
        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        // 完成签名并执行请求
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpPost);
            String bodyAsString = EntityUtils.toString(response.getEntity());// 响应体
            int statusCode = response.getStatusLine().getStatusCode();// 响应状态码
            if (statusCode == 200) { // 处理成功
                log.info("成功, 返回结果 = " + bodyAsString);
            } else if (statusCode == 204) { // 处理成功，无返回Body
                log.info("成功");
            } else {
                log.info("Native下单失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
                throw new IOException("request failed");
            }
            // 响应结果
            Map<String, String> resultMap = JSONUtil.toBean(bodyAsString, HashMap.class);
            // 二维码
            codeUrl = resultMap.get("code_url");
            // 保存二维码
            wxOrder.setCodeUrl(codeUrl);
            orderService.updateById(wxOrder);
            // 返回二维码
            NativeCodeVO vo = NativeCodeVO.builder().codeUrl(codeUrl).orderNo(wxOrder.getOrderNo()).build();
            return R.ok(vo);
        } catch (Exception e) {
            log.error("微信支付：统一下单失败...");
            throw new RuntimeException(e);
        } finally {
            // 重要：确保流被关闭
            if (response != null) {
                try {
                    response.close(); // 关闭输入流
                } catch (IOException e) {
                    System.err.println("关闭输入流时发生错误: " + e.getMessage());
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processOrder(Map<String, Object> map) {
        log.info("处理订单");
        // 解密报文
        String plainText = decryptFromResource(map);
        // 将明文转换成map
        HashMap<String, String> jsonMap = JSONUtil.toBean(plainText, HashMap.class);
        String orderNo = jsonMap.get("out_trade_no");
        /*在对业务数据进行状态检查和处理之前，
        要采用数据锁进行并发控制，
        以避免函数重入造成的数据混乱*/
        // 尝试获取锁：
        // 成功获取则立即返回true，获取失败则立即返回false。不必一直等待锁的释放
        if (lock.tryLock()) {
            try {
                // 处理重复的通知
                // 接口调用的幂等性：无论接口被调用多少次，产生的结果是一致的。
                String orderStatus = orderService.getOrderStatus(orderNo);
                if (!OrderStatus.NOTPAY.getType().equals(orderStatus)) {
                    return;
                }
                // 模拟通知并发
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 修改订单状态
                orderService.updateStatusByOrderNo(orderNo,OrderStatus.SUCCESS);
                // 记录支付日志
                // paymentInfoService.createPaymentInfo(plainText);
            } finally {
                // 要主动释放锁
                lock.unlock();
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processRefund(Map<String, Object> map) {
        log.info("退款单");
        // 解密报文
        String plainText = decryptFromResource(map);
        // 将明文转换成map
        HashMap<String, String> jsonMap = JSONUtil.toBean(plainText, HashMap.class);
        String orderNo = jsonMap.get("out_trade_no");
        if (lock.tryLock()) {
            try {
                String orderStatus = orderService.getOrderStatus(orderNo);
                if (!OrderStatus.REFUND_PROCESSING.getType().equals(orderStatus)) {
                    return;
                }
                // 更新订单状态
                orderService.updateStatusByOrderNo(orderNo,OrderStatus.REFUND_SUCCESS);
                // 更新退款单
                refundService.updateRefund(plainText);
            } finally {
                // 要主动释放锁
                lock.unlock();
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R cancelOrder(String orderId) {
        WxOrder wxOrder = orderService.getById(orderId);
        String orderNo = wxOrder.getOrderNo();
        // 调用微信支付的关单接口
        this.closeOrder(orderNo);
        // 更新商户端的订单状态
        return orderService.updateStatusByOrderNo(orderNo, OrderStatus.CANCEL);
    }

    @Override
    public R<OrderVO> getOrder(String orderNo) {
        log.info("查单接口调用 ===> {}", orderNo);
        /**
         * {"amount":{"currency":"CNY","payer_currency":"CNY","payer_total":1,"total":1},"appid":"wx74862e0dfcf69954","attach":"","bank_type":"OTHERS","mchid":"1558950191","out_trade_no":"ORDER_20251122194842729","payer":{"openid":"oHwsHuMpxTArU3I0vfB-unM9eyys"},"promotion_detail":[],"success_time":"2025-11-22T19:49:18+08:00","trade_state":"SUCCESS","trade_state_desc":"支付成功","trade_type":"NATIVE","transaction_id":"4200002878202511227719917780"}
         */
        String url = wxPayProperties.getDomain().concat(String.format(WxApiType.ORDER_QUERY_BY_NO.getType(), orderNo)).concat("?mchid=").concat(wxPayProperties.getMchId());
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept", "application/json");
        // 完成签名并执行请求
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpGet);
            String bodyAsString = EntityUtils.toString(response.getEntity());// 响应体
            int statusCode = response.getStatusLine().getStatusCode();// 响应状态码
            if (statusCode == 200) { // 处理成功
                log.info("成功, 返回结果 = " + bodyAsString);
            } else if (statusCode == 204) { // 处理成功，无返回Body
                log.info("成功");
            } else {
                log.info("查单接口调用,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
                throw new IOException("request failed");
            }
            JSONObject obj = JSONObject.parseObject(bodyAsString);
            Map<String, String> map = JSONObject.toJavaObject(obj, Map.class);
            OrderVO vo = OrderVO.builder().weChatPayState(map.get("trade_state")).weChatPayStateDesc(map.get("trade_state_desc")).orderNo(orderNo).build();
            return R.ok(vo);
        } catch (Exception e) {
            log.error("微信支付：微信订单查询失败...");
            throw new RuntimeException(e);
        } finally {
            // 重要：确保流被关闭
            if (response != null) {
                try {
                    response.close(); // 关闭输入流
                } catch (IOException e) {
                    System.err.println("关闭输入流时发生错误: " + e.getMessage());
                }
            }
        }
    }

    @Override
    public R<OrderVO> getRefundOrder(String no) {
        log.info("查询退款接口调用 ===> {}", no);
        String url = String.format(WxApiType.DOMESTIC_REFUNDS_QUERY.getType(), no);
        url = wxPayProperties.getDomain().concat(url);
        // 创建远程Get 请求对象
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept", "application/json");
        // 完成签名并执行请求
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpGet);
            String bodyAsString = EntityUtils.toString(response.getEntity());
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                //{"amount":{"currency":"CNY","discount_refund":0,"from":[],"payer_refund":1,"payer_total":1,"refund":1,"refund_fee":0,"settlement_refund":1,"settlement_total":1,"total":1},"channel":"ORIGINAL","create_time":"2025-11-20T12:33:29+08:00","funds_account":"UNAVAILABLE","out_refund_no":"REFUND_20251120123329359","out_trade_no":"ORDER_20251120111604747","promotion_detail":[],"refund_id":"50302505422025112088749938664","status":"SUCCESS","success_time":"2025-11-20T12:33:32+08:00","transaction_id":"4200002953202511206522507505","user_received_account":"支付用户零钱"}
                log.info("成功, 查询退款返回结果 = " + bodyAsString);
            } else if (statusCode == 204) {
                log.info("成功");
            } else {
                throw new RuntimeException("查询退款异常, 响应码 = " + statusCode + ", 查询退款返回结果 = " + bodyAsString);
            }
            JSONObject obj = JSONObject.parseObject(bodyAsString);
            Map<String, String> map = JSONObject.toJavaObject(obj, Map.class);
            OrderVO vo = OrderVO.builder().weChatPayState(map.get("status")).weChatPayStateDesc(map.get("user_received_account")).orderNo(no).build();
            return R.ok(vo);
        } catch (Exception e) {
            log.error("微信支付：微信订单（退款）查询失败...");
            throw new RuntimeException(e);
        } finally {
            // 重要：确保流被关闭
            if (response != null) {
                try {
                    response.close(); // 关闭输入流
                } catch (IOException e) {
                    System.err.println("关闭输入流时发生错误: " + e.getMessage());
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R refundOrder(OrderRefundsDTO dto) {
        log.info("用户申请退款...");
        Long id = dto.getId();
        WxOrder wxOrder = orderService.getById(id);
        String orderNo = wxOrder.getOrderNo();
        String reason = dto.getReason();
        // 创建退款单
        WxRefund refund = WxRefund.builder().refundNo(OrderNoUtils.getRefundNo()).orderNo(orderNo).reason(reason).totalFee(wxOrder.getTotalFee()).refund(wxOrder.getTotalFee()).build();
        refundService.save(refund);
        log.info("调用退款API");
        // 调用统一下单API
        String url = wxPayProperties.getDomain().concat(WxApiType.DOMESTIC_REFUNDS.getType());
        HttpPost httpPost = new HttpPost(url);
        // 请求body参数
        Map paramsMap = new HashMap();
        paramsMap.put("out_trade_no", orderNo);// 订单编号
        paramsMap.put("out_refund_no", refund.getRefundNo());// 退款单编号
        paramsMap.put("reason", reason);// 退款原因
        paramsMap.put("notify_url", wxPayProperties.getNotifyDomain().concat(WxNotifyType.REFUND_NOTIFY.getType()));// 退款通知地址
        Map amountMap = new HashMap();
        amountMap.put("refund", refund.getRefund());// 退款金额
        amountMap.put("total", refund.getTotalFee());// 原订单金额
        amountMap.put("currency", "CNY");// 退款币种
        paramsMap.put("amount", amountMap);
        // 将参数转换成json字符串
        String jsonParams = JSONUtil.toJsonStr(paramsMap);
        log.info("请求参数 ===> {}" + jsonParams);
        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");// 设置请求报文格式
        httpPost.setEntity(entity);// 将请求报文放入请求对象
        httpPost.setHeader("Accept", "application/json");// 设置响应报文格式
        // 完成签名并执行请求，并完成验签
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpPost);
            // 解析响应结果
            String bodyAsString = EntityUtils.toString(response.getEntity());
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                log.info("成功, 退款返回结果 = " + bodyAsString);
            } else if (statusCode == 204) {
                log.info("成功");
            } else {
                throw new RuntimeException("退款异常, 响应码 = " + statusCode + ", 退款返回结果 = " + bodyAsString);
            }
            // 更新订单状态
            wxOrder.setOrderStatus(OrderStatus.REFUND_PROCESSING.getType());
            boolean flag = orderService.updateById(wxOrder);
            // 更新退款单
            refundService.updateRefund(bodyAsString);
            return flag ? R.ok(true, "正在退款中，请稍后在微信中查看") : R.fail("退款失败");
        } catch (Exception e) {
            log.error("微信支付：微信订单退款失败...");
            throw new RuntimeException(e);
        } finally {
            // 重要：确保流被关闭
            if (response != null) {
                try {
                    response.close(); // 关闭输入流
                } catch (IOException e) {
                    System.err.println("关闭输入流时发生错误: " + e.getMessage());
                }
            }
        }
    }

    @Override
    public void checkOrderStatus(String orderNo) throws Exception {
        log.warn("根据订单号核实订单状态 ===> {}", orderNo);
        OrderVO orderRes = this.getOrder(orderNo).getResult();
        String tradeState = orderRes.getWeChatPayState();
        // 判断订单状态
        if (WxTradeState.SUCCESS.getType().equals(tradeState)) {
            log.warn("核实订单已支付 ===> {}", orderNo);
            // 如果确认订单已支付则更新本地订单状态
            orderService.updateStatusByOrderNo(orderNo, OrderStatus.SUCCESS);
            // 记录支付日志
            // paymentInfoService.createPaymentInfo(result);
        }
        if (WxTradeState.NOTPAY.getType().equals(tradeState)) {
            log.warn("核实订单未支付 ===> {}", orderNo);
            // 如果订单未支付，则调用关单接口
            this.closeOrder(orderNo);
            // 更新本地订单状态
            orderService.updateStatusByOrderNo(orderNo, OrderStatus.CLOSED);
        }
    }

    @Override
    public void checkRefundStatus(String refundNo) throws Exception {
    }

    @Override
    public String queryBill(String billDate, String type) {
        log.warn("申请账单接口调用 {}", billDate);
        String url = "";
        if ("tradebill".equals(type)) {
            url = WxApiType.TRADE_BILLS.getType();
        } else if ("fundflowbill".equals(type)) {
            url = WxApiType.FUND_FLOW_BILLS.getType();
        } else {
            throw new RuntimeException("不支持的账单类型");
        }
        url = wxPayProperties.getDomain().concat(url).concat("?bill_date=").concat(billDate);
        // 创建远程Get 请求对象
        HttpGet httpGet = new HttpGet(url);
        httpGet.addHeader("Accept", "application/json");
        // 使用wxPayClient发送请求得到响应
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpGet);
            String bodyAsString = EntityUtils.toString(response.getEntity());
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                log.info("成功, 申请账单返回结果 = " + bodyAsString);
            } else if (statusCode == 204) {
                log.info("成功");
            } else {
                throw new RuntimeException("申请账单异常, 响应码 = " + statusCode + ", 申请账单返回结果 = " + bodyAsString);
            }
            // 获取账单下载地址
            Map<String, String> resultMap = JSONUtil.toBean(bodyAsString, HashMap.class);
            return resultMap.get("download_url");
        } catch (Exception e) {
            log.error("微信支付：微信账单查询失败...");
            throw new RuntimeException(e);
        } finally {
            // 重要：确保流被关闭
            if (response != null) {
                try {
                    response.close(); // 关闭输入流
                } catch (IOException e) {
                    System.err.println("关闭输入流时发生错误: " + e.getMessage());
                }
            }
        }
    }

    @Override
    public R downloadBill(String billDate, String type) {
        log.warn("下载账单接口调用 {}, {}", billDate, type);
        // 获取账单url地址
        String downloadUrl = this.queryBill(billDate, type);
        // 创建远程Get 请求对象
        HttpGet httpGet = new HttpGet(downloadUrl);
        httpGet.addHeader("Accept", "application/json");
        // 使用wxPayClient发送请求得到响应
        // CloseableHttpResponse response = wxPayNoSignClient.execute(httpGet);
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpGet);
            String bodyAsString = EntityUtils.toString(response.getEntity());
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                log.info("成功, 下载账单返回结果 = " + bodyAsString);
            } else if (statusCode == 204) {
                log.info("成功");
            } else {
                throw new RuntimeException("下载账单异常, 响应码 = " + statusCode + ", 下载账单返回结果 = " + bodyAsString);
            }
            return R.ok(bodyAsString);
        } catch (Exception e) {
            log.error("微信支付：微信账单查询失败..." + e.getMessage());
            throw new RuntimeException(e);
        } finally {
            // 重要：确保流被关闭
            if (response != null) {
                try {
                    response.close(); // 关闭输入流
                } catch (IOException e) {
                    System.err.println("关闭输入流时发生错误: " + e.getMessage());
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R confirmOrder(Long id) {
        WxOrder wxOrder = orderService.getById(id);
        // 判断订单状态-本地
        if (!OrderStatus.NOTPAY.getType().equals(wxOrder.getOrderStatus())) {
            return R.fail("当前订单非未支付状态，不允许确定");
        }
        // 判断订单状态-微信方面
        String orderNo = wxOrder.getOrderNo();
        R<OrderVO> vor = this.getOrder(orderNo);
        OrderVO result = vor.getResult();
        if (WxTradeState.SUCCESS.getType().equals(result.getWeChatPayState())) {
            log.warn("核实订单已支付 ===> {}", orderNo);
            wxOrder.setOrderStatus(OrderStatus.SUCCESS.getType());
            // 记录支付日志
            // paymentInfoService.createPaymentInfo(result);
        }
        // 修改订单状态
        boolean flag = orderService.updateById(wxOrder);
        return flag ? R.ok(true, "操作成功") : R.fail("操作失败");
    }

    @Override
    public String nativeNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>();// 应答对象
        try {
            // 处理通知参数
            String body = HttpUtils.readData(request);
            Map<String, Object> bodyMap = JSONUtil.toBean(body, HashMap.class);
            String requestId = (String) bodyMap.get("id");
            log.info("微信支付成功通知：通知的id ===> {}", requestId);
            // log.info("支付通知的完整数据 ===> {}", body);
            // int a = 9 / 0;
            // 签名的验证
            WechatPay2ValidatorForRequest weReq = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if (!weReq.validate(request)) {
                log.error("通知验签失败");
                // 失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return JSONUtil.toJsonStr(map);
            }
            log.info("通知验签成功");
            // 处理订单
            this.processOrder(bodyMap);
            // 应答超时
            // 模拟接收微信端的重复通知
            // TimeUnit.SECONDS.sleep(5);
            // 成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return JSONUtil.toJsonStr(map);
        } catch (Exception e) {
            e.printStackTrace();
            // 失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return JSONUtil.toJsonStr(map);
        }
    }

    @Override
    public String refundsNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>();// 应答对象
        try {
            // 处理通知参数
            String body = HttpUtils.readData(request);
            Map<String, Object> bodyMap = JSONUtil.toBean(body, HashMap.class);
            String requestId = (String) bodyMap.get("id");
            log.info("微信退款成功通知：通知的id ===> {}", requestId);
            // log.info("支付通知的完整数据 ===> {}", body);
            // int a = 9 / 0;
            // 签名的验证
            WechatPay2ValidatorForRequest weReq = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if (!weReq.validate(request)) {
                log.error("通知验签失败");
                // 失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return JSONUtil.toJsonStr(map);
            }
            log.info("通知验签成功");
            // 处理退款单
            this.processRefund(bodyMap);
            // 成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return JSONUtil.toJsonStr(map);
        } catch (Exception e) {
            e.printStackTrace();
            // 失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return JSONUtil.toJsonStr(map);
        }
    }

    @Override
    public Map<String, Object> nativePayV2(WxOrderDTO dto) throws Exception {
        log.info("生成订单");
        // 生成订单
        WxOrder wxOrder = orderService.addOrder(dto);
        String codeUrl = wxOrder.getCodeUrl();
        if (wxOrder != null && !StringUtils.isEmpty(codeUrl)) {
            log.info("订单已存在，二维码已保存");
            // 返回二维码
            Map<String, Object> map = new HashMap<>();
            map.put("codeUrl", codeUrl);
            map.put("orderNo", wxOrder.getOrderNo());
            return map;
        }
        log.info("调用统一下单API");
        HttpClientUtils client = new HttpClientUtils(wxPayProperties.getDomain().concat(WxApiType.NATIVE_PAY_V2.getType()));
        // 组装接口参数
        Map<String, String> params = new HashMap<>();
        params.put("appid", wxPayProperties.getAppid());// 关联的公众号的appid
        params.put("mch_id", wxPayProperties.getMchId());// 商户号
        params.put("nonce_str", WXPayUtil.generateNonceStr());// 生成随机字符串
        params.put("body", wxOrder.getTitle());
        params.put("out_trade_no", wxOrder.getOrderNo());
        // 注意，这里必须使用字符串类型的参数（总金额：分）
        String totalFee = wxOrder.getTotalFee() + "";
        params.put("total_fee", totalFee);
        params.put("spbill_create_ip", dto.getRemoteAddr());
        params.put("notify_url", wxPayProperties.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY_V2.getType()));
        params.put("trade_type", "NATIVE");
        // 将参数转换成xml字符串格式：生成带有签名的xml格式字符串
        String xmlParams = WXPayUtil.generateSignedXml(params, wxPayProperties.getPartnerKey());
        log.info("\n xmlParams：\n" + xmlParams);
        client.setXmlParam(xmlParams);// 将参数放入请求对象的方法体
        client.setHttps(true);// 使用https形式发送
        client.post();// 发送请求
        String resultXml = client.getContent();// 得到响应结果
        log.info("\n resultXml：\n" + resultXml);
        // 将xml响应结果转成map对象
        Map<String, String> resultMap = WXPayUtil.xmlToMap(resultXml);
        // 错误处理
        if ("FAIL".equals(resultMap.get("return_code")) || "FAIL".equals(resultMap.get("result_code"))) {
            log.error("微信支付统一下单错误 ===> {} ", resultXml);
            throw new RuntimeException("微信支付统一下单错误");
        }
        // 二维码
        codeUrl = resultMap.get("code_url");
        // 保存二维码
        wxOrder.setCodeUrl(codeUrl);
        orderService.updateById(wxOrder);
        // 返回二维码
        Map<String, Object> map = new HashMap<>();
        map.put("codeUrl", codeUrl);
        map.put("orderNo", wxOrder.getOrderNo());
        return map;
    }

    /**
     * 对称解密
     *
     * @param bodyMap
     * @return
     */
    public String decryptFromResource(Map<String, Object> bodyMap) {
        log.info("密文解密");
        // 通知数据
        Map<String, String> resourceMap = (Map) bodyMap.get("resource");
        // 数据密文
        String ciphertext = resourceMap.get("ciphertext");
        // 随机串
        String nonce = resourceMap.get("nonce");
        // 附加数据
        String associatedData = resourceMap.get("associated_data");
        log.info("密文 ===> {}", ciphertext);
        AesUtil aesUtil = new AesUtil(wxPayProperties.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        String plainText = null;
        try {
            plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        log.info("明文 ===> {}", plainText);
        return plainText;
    }

    private void closeOrder(String orderNo) {
        log.info("关单接口的调用，订单号 ===> {}", orderNo);
        // 创建远程请求对象
        String url = String.format(WxApiType.CLOSE_ORDER_BY_NO.getType(), orderNo);
        url = wxPayProperties.getDomain().concat(url);
        HttpPost httpPost = new HttpPost(url);
        // 组装json请求体
        Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("mchid", wxPayProperties.getMchId());
        String jsonParams = JSONUtil.toJsonStr(paramsMap);
        log.info("请求参数 ===> {}", jsonParams);
        // 将请求参数设置到请求对象中
        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        // 完成签名并执行请求
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();// 响应状态码
            if (statusCode == 200) { // 处理成功
                log.info("成功200");
            } else if (statusCode == 204) { // 处理成功，无返回Body
                log.info("成功204");
            } else {
                log.info("Native下单失败,响应码 = " + statusCode);
                throw new IOException("request failed");
            }
        } catch (Exception e) {
            log.error("微信支付：微信关闭订单失败..." + e.getMessage());
            throw new RuntimeException(e);
        } finally {
            // 重要：确保流被关闭
            if (response != null) {
                try {
                    response.close(); // 关闭输入流
                } catch (IOException e) {
                    System.err.println("关闭输入流时发生错误: " + e.getMessage());
                }
            }
        }
    }
}
